﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Workflow.ComponentModel;
using Nsf.Samples.RetryActivitySample.Service.Configuration;

namespace Nsf.Samples.RetryActivitySample.Service.Infrastructure
{
    /// <summary>
    /// Менеджер типов рабочих процессов
    /// </summary>
    internal class WorkflowTypesManager
    {
        #region InternalState

        private static readonly Dictionary<String, String> _descriptionToTypeNameMap;
        private static readonly Dictionary<String, Type> _descriptionToTypeMap;

        #endregion

        #region Initialization

        static WorkflowTypesManager()
        {
            _descriptionToTypeNameMap = new Dictionary<String, String>();
            _descriptionToTypeMap = new Dictionary<String, Type>();

            InitializeMaps();
        }

        private static void InitializeMaps()
        {
            var workflowTypes = ConfigurationManager.GetSection("WorkflowTypes") as WorkflowTypes;
            if (workflowTypes != null)
            {
                foreach (var workflowType in workflowTypes.Types)
                {
                    _descriptionToTypeNameMap.Add(workflowType.Name.ToLower(), workflowType.Type);
                }
            }
        }

        #endregion

        #region PublicMethods

        /// <summary>
        /// Возвращает тип рабочего потока в соовтетствии с его описанием
        /// </summary>
        /// <param name="typeDescription">Описание типа рабочего потока</param>
        /// <returns>Тип рабочего потока</returns>
        /// </exception>
        public static Type GetWorkflowType(String typeDescription)
        {
            typeDescription = typeDescription.ToLower();
            Type result;
            if (_descriptionToTypeMap.TryGetValue(typeDescription, out result))
                return result;

            String type;
            if (_descriptionToTypeNameMap.TryGetValue(typeDescription, out type))
            {
                result = Type.GetType(type, false, false);
                if (result == null)
                    throw new TypeLoadException(String.Format("Не удалось загрузить тип '{0}'", type));
                if (!typeof(Activity).IsAssignableFrom(result))
                    throw new TypeLoadException(String.Format("Тип '{0}' должен быть прямым или косвенным наследником '{1}'", type, typeof(Activity).AssemblyQualifiedName));
                _descriptionToTypeMap.Add(typeDescription, result);
                return result;
            }
            throw new ApplicationException(String.Format("Тип, соответствующий описанию '{0}', не найден", typeDescription));
        }

        #endregion
    }
}
